package boardgamer.common.board;

import com.google.common.collect.Table;

import java.io.Serializable;
import java.util.Collection;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Represents a board with tiles.
 *
 * @author garysoed
 */
public abstract class TiledBoard<T> implements Serializable {

  /**
   * Factory used by {@link TiledBoard} to generate tiles.
   *
   * @author garysoed
   */
  public interface TileFactory<T> extends Serializable {
    T createTile(int x, int y);

    T copyTile(T tile);
  }

  protected final TileFactory<T> tileFactory;

  // For serialization
  protected TiledBoard() {
    this.tileFactory = new TileFactory<T>() {
      @Override
      public T createTile(int x, int y) {
        throw new UnsupportedOperationException("Unsupported");
      }

      @Override
      public T copyTile(T tile) {
        throw new UnsupportedOperationException("Unsupported");
      }
    };
  }

  protected TiledBoard(TileFactory<T> tileFactory) {
    this.tileFactory = checkNotNull(tileFactory, "tileFactory");
  }

  public T getTile(int x, int y) {
    checkArgument(hasTile(x, y), "No tile at position (" + x + ", " + y + ")");
    return findTile(x, y);
  }

  public abstract Collection<T> getTiles();

  public T copyTile(int x, int y) {
    return tileFactory.copyTile(getTile(x, y));
  }

  public abstract boolean hasTile(int x, int y);

  public abstract Table<Integer, Integer, T> getBoard();

  protected abstract T findTile(int x, int y);
}
